Rust: unsafe
code:例.rs
pub unsafe fn from_bytes_unchecked(bytes: Vec<u8>) -> Ascii {
Ascii(bytes)
}
code:rs
unsafe {
// ...
}
GPT-4.icon
unsafeとは?
Rustはメモリ安全性を保証するために厳格なコンパイル時チェックを行います。
しかし、特定の低レベル操作やパフォーマンスの最適化のために、この安全性を一部無効にする必要が生じる場合があります。
そこで登場するのがunsafeキーワードです。
unsafeブロックやunsafe関数を使用することで、Rustのコンパイラによる一部の安全性チェックを回避し、開発者が責任を持って安全性を確保することが可能になります。
unsafeが必要な理由
1. 低レベルのメモリ操作: 生ポインタの操作や、直接メモリにアクセスする必要がある場合。
2. 外部ライブラリとの連携: C言語などの外部コードとインターフェースする際。
3. パフォーマンス最適化: 高速化のために安全チェックを省略する場合。
unsafeで許可される操作
生ポインタのデリファレンス: *const Tや*mut Tといった生ポインタを直接操作。
外部関数の呼び出し: externブロック内の関数を呼び出す。
静的変数の変更: 不変とされている静的変数を変更。
unsafe関数やメソッドの呼び出し。
安全性の確保
unsafeを使用する際は、以下の点に注意して安全性を確保する必要があります:
データ競合の回避: 複数のスレッドから同時にアクセスされても問題が起きないようにする。
有効なメモリアドレスの使用: ポインタが有効なメモリを指していることを保証。
正しい外部関数の使用: 外部ライブラリの仕様に従って正しく関数を呼び出す。
サンプルコード
以下に、unsafeを使用して生ポインタをデリファレンスする簡単な例を示します。
code:rust
fn main() {
let x = 42;
let ptr = &x as *const i32;
unsafe {
// 生ポインタをデリファレンスして値を取得
println!("値: {}", *ptr);
}
}
1. xという整数を定義し、その参照を生ポインタptrに変換しています。
2. unsafeブロック内で、生ポインタptrをデリファレンスして値を取得し、表示しています。
3. unsafeブロックを使用することで、コンパイラに対して「ここで安全性を自分で保証します」と伝えています。
型安全性の保守的な部分を一部緩めるイメージ
バグはないんだから、型検査緩めてくれよ!ってやる
だからunsafeがあるのが一概に悪いというわけではない
ただ、コンパイラのサポートを一部得られないことを意味する
"Rust 研究者" として個人的に「Rust で困ったらガンガン unsafe を使えばいい」主義を応援しています
Rust の軽量な静的検査のもとで無条件に安全なものだけが safe で、unsafe はそれ以外の全てなので、「unsafe は即危険」ではなくて、多くの場合に何らかの条件のもとで安全性が担保されます
Rust の単純な静的検査でカバーしきれないのはむしろ自然なことなので、臆せず unsafe を使えばいいと思います
関数はデフォルトで unsafe にしておいて、「この所有権型で無条件で安全になる」と確信できる関数だけ safe にしていく方針を取ると、気が楽になると思います
仮に unsafe を使いまくっていたとしても、多くの場所で安全性が担保されるおかげで本当に危険な場所だけ注意すれば良くなるし、Rust を使う価値が十分にあると思います
爽快に unsafe を使いこなして、Rust をガンガン書いていきましょう